package cn.stylefeng.guns.modular.tao.api;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

import org.apache.commons.codec.binary.Base64;
import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.security.*;
import java.util.*;

public class Utils {

    /**
     * 定义char数组,16进制对应的基本字符
     */
    private static final char[] HEX_DIGITS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd',
            'e', 'f' };

    // 算法名称
    static  final String KEY_ALGORITHM = "AES";
    // 加解密算法/模式/填充方式
    static  final String algorithmStr = "AES/CBC/PKCS7Padding";
    private static Key key;
    private static Cipher cipher;
    boolean isInited = false;

    public static void init(byte[] keyBytes) {

        // 如果密钥不足16位，那么就补足.  这个if 中的内容很重要
        int base = 16;
        if (keyBytes.length % base != 0) {
            int groups = keyBytes.length / base + (keyBytes.length % base != 0 ? 1 : 0);
            byte[] temp = new byte[groups * base];
            Arrays.fill(temp, (byte) 0);
            System.arraycopy(keyBytes, 0, temp, 0, keyBytes.length);
            keyBytes = temp;
        }
        // 初始化
        Security.addProvider(new BouncyCastleProvider());
        // 转化成JAVA的密钥格式
        key = new SecretKeySpec(keyBytes, KEY_ALGORITHM);
        try {
            // 初始化cipher
            cipher = Cipher.getInstance(algorithmStr, "BC");
        } catch (NoSuchAlgorithmException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (NoSuchProviderException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    /**
     * 加密方法
     *      --使用默认iv时
     * @param content
     *            要加密的字符串
     * @param keyBytes
     *            加密密钥
     * @return
     */
    public static byte[] AES(byte[] content, byte[] keyBytes ,byte[] iv) {
        byte[] encryptedText =  encryptOfDiyIV(content,keyBytes,iv);
        return encryptedText;
    }


    /**
     * 解密方法
     *      --使用默认iv时
     * @param encryptedData
     *            要解密的字符串
     * @param keyBytes
     *            解密密钥
     * @return
     */
    public static byte[] UnAES(byte[] encryptedData, byte[] keyBytes,byte[] iv) {
        byte[] encryptedText = decryptOfDiyIV(encryptedData,keyBytes,iv);
        return encryptedText;
    }
    /**
     * 加密方法
     *      ---自定义对称解密算法初始向量 iv
     * @param content
     *              要加密的字符串
     * @param keyBytes
     *              加密密钥
     * @param ivs
     *         自定义对称解密算法初始向量 iv
     * @return 加密的结果
     */
    public static byte[] encryptOfDiyIV(byte[] content, byte[] keyBytes, byte[] ivs) {
        byte[] encryptedText = null;
        init(keyBytes);
        System.out.println("IV：" + new String(ivs));
        try {
            cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(ivs));
            encryptedText = cipher.doFinal(content);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return encryptedText;
    }
    /**
     * 解密方法
     *
     * @param encryptedData
     *            要解密的字符串
     * @param keyBytes
     *            解密密钥
     * @param ivs
     *         自定义对称解密算法初始向量 iv
     * @return
     */
    public static byte[] decryptOfDiyIV(byte[] encryptedData, byte[] keyBytes,byte[] ivs) {
        byte[] encryptedText = null;
        init(keyBytes);
        System.out.println("IV：" + new String(ivs));
        try {
            cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(ivs));
            encryptedText = cipher.doFinal(encryptedData);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return encryptedText;
    }
    // 将16进制字符串转换成字节数组
    private static byte[] hex2byte(String inputString) {

        if (inputString == null || inputString.length() < 2) {
            return new byte[0];
        }
        inputString = inputString.toLowerCase();
        int l = inputString.length() / 2;
        byte[] result = new byte[l];
        for (int i = 0; i < l; ++i) {
            String tmp = inputString.substring(2 * i, 2 * i + 2);
            result[i] = (byte) (Integer.parseInt(tmp, 16) & 0xFF);
        }
        return result;
    }

    /**
     * 将二进制转换成16进制
     *
     * @param buf
     * @return
     */
    public static String parseByte2HexStr(byte buf[]) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < buf.length; i++) {
            String hex = Integer.toHexString(buf[i] & 0xFF);
            if (hex.length() == 1) {
                hex = '0' + hex;
            }
            sb.append(hex.toUpperCase());
        }
        return sb.toString();
    }

    /**
     * 将16进制转换为二进制
     *
     * @param hexStr
     * @return
     */
    public static byte[] parseHexStr2Byte(String hexStr) {
        if (hexStr.length() < 1)
            return null;
        byte[] result = new byte[hexStr.length() / 2];
        for (int i = 0; i < hexStr.length() / 2; i++) {
            int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16);
            int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2), 16);
            result[i] = (byte) (high * 16 + low);
        }
        return result;
    }

    /**
     * 　　* 利用java原生的摘要实现SHA256加密
     * 　　* @param str 加密后的报文
     * 　　* @return
     */
    public static String SHA256(String str) {
        MessageDigest messageDigest;
        String encodeStr = "";
        try {
            messageDigest = MessageDigest.getInstance("SHA-256");
            messageDigest.update(str.getBytes("UTF-8"));
            encodeStr = byte2Hex(messageDigest.digest());
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return encodeStr;
    }

    /**
     * 　　* 将byte转为16进制
     * 　　* @param bytes
     * 　　* @return
     */
    private static String byte2Hex(byte[] bytes) {
        StringBuffer stringBuffer = new StringBuffer();
        String temp = null;
        for (int i = 0; i < bytes.length; i++) {
            temp = Integer.toHexString(bytes[i] & 0xFF);
            if (temp.length() == 1) {
//1得到一位的进行补0操作
                stringBuffer.append("0");
            }
            stringBuffer.append(temp);
        }
        return stringBuffer.toString();
    }

    public static void main(String[] args) {
        String token = getToken();
        System.out.println(token);
    }

    /**
     * 获取授权认证码
     */
    public static String getToken() {
        String token = null;
        String authcode = null;
        String p = null;
        String result = null;
        String sign = null;
        String appkey = "68943923115886070418838901844741";
        String signkey = "lezitiancheng";
        String KEY = "ONxYDyNaCoyTzsp83JoQ3YYuMPHxk3j7";
        String IV = "yNaCoyTzsp83JoQ3";

        try {
            Map<String, String> map = new HashMap<>();
            map.put("CompanyName", "testmall");
            map.put("UserId", "test");
            map.put("Password", "grasp@101");
            map.put("TimeStamp", "2019-05-05 10:59:26");
            String json = JSON.toJSONString(map);
            byte[] data = json.getBytes();
            byte[] key = KEY.getBytes();
            byte[] iv = IV.getBytes();
            byte[] b = AES(data, key, iv);
            p =  Base64.encodeBase64String(b);
            Map<String, String> map1 = new HashMap<>();
            String pq="50erC7OaZyMLFLQNtWjRb/cKjP4KtH9BMbUvs50aCUB6yYNFuW8CNAwAJz36USl/TkcMf1Imjqs8MTqvrx0NNkLIu2KoZ0DIkGdyWB6dYh5ZQUpyN9bogpxTgrRMNjuxjlcH+mpoF58Fuab25Gzdtg==";
            map1.put("appkey", appkey);
            map1.put("p", pq);
            map1.put("signkey", signkey);
            String json1 = JSON.toJSONString(map1);
            sign = SHA256(json1);
            String qqq="12d938f0d1819a9f17b18faf13d4becc92a140ebaf530cf5c896469a86c530f6";
            result = sendPost("http://ca.mygjp.com:8002/api/login", "appkey=" + appkey + "&p=" + p + "&sign=" + qqq + "");

            JSONObject result1 = JSONObject.parseObject(result);
            if ("false".equals(result1.get("iserror"))) {
                String result2 = result1.getString("response");
                JSONObject result3 = JSON.parseObject(result2);
                authcode = result3.getString("authcode");
            }
            if (authcode != null) {
                Map<String, String> map3 = new HashMap<>();
                map3.put("TimeStamp", "2016-10-01 10:24:40");
                map3.put("GrantType", "auth_token");
                map3.put("AuthParam", authcode);
                String json2 = JSON.toJSONString(map3);

                byte[] data1 = json2.getBytes();
                byte[] b1 = AES(data1, key, iv);
                String p1 = new String(b1);
                Map<String, String> map4 = new HashMap<>();
                map4.put("appkey", appkey);
                map4.put("p", p1);
                map4.put("signkey", signkey);
                String json3 = JSON.toJSONString(map4);
                sign = SHA256(json3);
                result = sendPost(" http://ca.mygjp.com:8002/api/token", "appkey=" + appkey + "&p=" + p + "&sign=" + sign + "");
                JSONObject result3 = JSONObject.parseObject(result);
                if ("false".equals(result3.get("iserror"))) {
                    String result4 = result3.getString("response");
                    JSONObject result5 = JSON.parseObject(result4);
                    String tokens = result5.getString("response");
                    byte[] b2 = tokens.getBytes();
                    byte[] r = UnAES(b2, key,iv);
                    String result6 = new String(r);
                    JSONObject result8 = JSON.parseObject(result6);
                    token = result8.getString("auth_token");
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return token;
    }

    /**
     * 向指定 URL 发送POST方法的请求
     *
     * @param url   发送请求的 URL
     * @param param 请求参数，请求参数应该是 name1=value1&name2=value2 的形式。
     * @return 所代表远程资源的响应结果
     */
    public static String sendPost(String url, String param) {
        PrintWriter out = null;
        BufferedReader in = null;
        String result = "";
        try {
            URL realUrl = new URL(url);
            // 打开和URL之间的连接
            URLConnection conn = realUrl.openConnection();
            // 设置通用的请求属性
            conn.setRequestProperty("accept", "*/*");
            conn.setRequestProperty("connection", "Keep-Alive");
            conn.setRequestProperty("user-agent",
                    "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
            // 发送POST请求必须设置如下两行
            conn.setDoOutput(true);
            conn.setDoInput(true);
            // 获取URLConnection对象对应的输出流
            out = new PrintWriter(conn.getOutputStream());
            // 发送请求参数
            out.print(param);
            // flush输出流的缓冲
            out.flush();
            // 定义BufferedReader输入流来读取URL的响应
            in = new BufferedReader(
                    new InputStreamReader(conn.getInputStream(), "UTF-8"));
            String line;
            while ((line = in.readLine()) != null) {
                result += line;
            }
        } catch (Exception e) {
            System.out.println("发送 POST 请求出现异常！" + e);
            e.printStackTrace();
        }
        //使用finally块来关闭输出流、输入流
        finally {
            try {
                if (out != null) {
                    out.close();
                }
                if (in != null) {
                    in.close();
                }
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
        return result;
    }

    /**
     * 管家婆签名算法
     */
    public static String sign(Map<String, String> map, String signkey) {
        String sign = "";
        try {
            Map<String, String> signMap = sortMapByKey(map, true);
            List<String> keys = new ArrayList<String>(signMap.keySet());
            for (int i = 0; i < keys.size(); i++) {
                sign += keys.get(i) + signMap.get(keys.get(i));
            }
            sign += signkey;
            sign = new String(sign.getBytes("gbk"), "utf-8");
            sign = getMD5String(sign);


        } catch (Exception e) {
            e.printStackTrace();
        }
        return sign;
    }


    /**
     * 使用 Map 按 Key 进行排序
     *
     * @param oriMap 排序 Map 集合
     * @param isRise 是否按照升序排序
     */
    public static Map<String, String> sortMapByKey(Map<String, String> oriMap, final boolean isRise) {
        if (oriMap == null || oriMap.isEmpty()) {
            return null;
        }
        Map<String, String> sortMap = new TreeMap<>(new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                if (isRise) {
                    // 升序排序
                    return o1.compareTo(o2);
                } else {
                    // 降序排序
                    return o2.compareTo(o1);
                }
            }
        });
        sortMap.putAll(oriMap);
        return sortMap;
    }

    /**
     * md5加密
     * @param str 需要加密的数据
     * @return 加密结果
     * @author sucb
     * @date 2017年7月26日下午5:12:16
     */
    public static String getMD5String(String str) {
        MessageDigest messageDigest = null;
        try {
            messageDigest = MessageDigest.getInstance("MD5");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            return null;
        }
        messageDigest.update(str.getBytes());
        return byteArray2HexString(messageDigest.digest());
    }

    /**
     * MD5加密结果（由byte转换成String）
     * @param bytes md5加密后得到的数组
     * @return md5加密结果
     * @author sucb
     * @date 2017年7月26日下午5:12:09
     */
    private static String byteArray2HexString(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) {
            sb.append(HEX_DIGITS[(b & 0xf0) >> 4]).append(HEX_DIGITS[(b & 0x0f)]);
        }
        return sb.toString();
    }
}
